﻿/*  
	------------------------------------------------------------------------
	 NQ Core Library Test Suite
	
	 Homepage: http://www.awzhome.de/
	------------------------------------------------------------------------
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of NQ Core Library.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using AWZhome.NQ.Core.Testing;

namespace AWZhome.NQ.Core.Tests
{
	[TestFixture]
	public class NQServiceManagerImplTest
	{
		private NQServiceManagerImpl _servManager;

		public void SetupManager(NQHostMode hostMode, INQComponentInfo[] compInfos, INQServiceInfo[] servInfos)
		{
			// Initializing of NQ service manager with the dummy component loader
			_servManager = new NQServiceManagerImpl(new string[] { }, hostMode, new NQDummyComponentLoader(compInfos, servInfos));
			NQServiceManager.SetImplementation(_servManager);

			// Load all components in plugin directory	
			_servManager.LoadComponents();
			_servManager.LoadServices();
		}

		[TearDown]
		public void DestroyManager()
		{
			if (_servManager != null)
			{
				_servManager.DestroyServices();
			}
		}

		[Test]
		public void GetService_MustReturnEqualInstances()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSimple)
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { singletonServ });

			// Two instances of TestService.Singleton returned by GetService() must be the same
			object singleton1 = NQServiceManager.Instance.GetService<object>(typeof(TestServiceTypeSimple));
			object singleton2 = NQServiceManager.Instance.GetService<object>(typeof(TestServiceTypeSimple));

			Assert.That(singleton1, Is.EqualTo(singleton2));
		}

		[Test]
		public void MustLoadConsoleComponentsOnly()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp1 = new NQComponentInfo()
			{
				Name = "TestComponent1",
				Category = NQHostMode.General
			};
			NQComponentInfo testComp2 = new NQComponentInfo()
			{
				Name = "TestComponent2",
				Category = NQHostMode.GUI
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp1, testComp2 },
				new INQServiceInfo[] { });

			// TestComponent1 must be loaded, but TestComponent2 must not (it's category is NQHostMode.GUI)
			Assert.That(_servManager.IsComponentLoaded("TestComponent1"), "TestComponent1 must be registered.");
			Assert.That(!_servManager.IsComponentLoaded("TestComponent2"), "TestComponent2 must not be registered.");
		}

		[Test]
		public void MustLoadConsoleServicesOnly()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo consoleServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceCategory = NQHostMode.Console,
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo guiServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceCategory = NQHostMode.GUI,
				ServiceType = typeof(TestServiceTypeSimple2)
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { consoleServ, guiServ });

			// "NQCoreTest.Test4" must be loaded, but "NQCoreTest.ConsoleTest1" must not (it's category is NQHostMode.GUI)
			Assert.That(_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple1)),
				"TestServiceTypeSimple1 must be registered.");
			Assert.That(!_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple2)),
				"TestServiceTypeSimple2 must not be registered.");
		}

		[Test]
		public void MustLoadGUIComponents()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp1 = new NQComponentInfo()
			{
				Name = "TestComponent1",
				Category = NQHostMode.General
			};
			NQComponentInfo testComp2 = new NQComponentInfo()
			{
				Name = "TestComponent2",
				Category = NQHostMode.GUI
			};

			this.SetupManager(NQHostMode.GUI,
				new INQComponentInfo[] { testComp1, testComp2 },
				new INQServiceInfo[] { });

			// NQTestComponent1 and NQTestComponent2 must be loaded
			Assert.That(_servManager.IsComponentLoaded("TestComponent1"), "TestComponent1 must be registered.");
			Assert.That(_servManager.IsComponentLoaded("TestComponent2"), "TestComponent2 must be registered.");
		}

		[Test]
		public void MustLoadGUIServices()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo consoleServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo guiServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceCategory = NQHostMode.GUI,
				ServiceType = typeof(TestServiceTypeSimple2)
			};

			this.SetupManager(NQHostMode.GUI,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { consoleServ, guiServ });

			// "TestService.Console" and "TestService.GUI" must be registered
			Assert.That(_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple1)),
				"TestServiceTypeSimple2 must be registered.");
			Assert.That(_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple2)),
				"TestServiceTypeSimple2 must be registered.");
		}

		[Test]
		public void MustNotLoadComponentWithUnsatisfiedRequirement()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp1 = new NQComponentInfo()
			{
				Name = "TestComponent1",
				Version = new Version(1, 0, 0, 0)
			};
			NQComponentInfo testComp2 = new NQComponentInfo()
			{
				Name = "TestComponent2",
				Requires = new NQComponentRequirement[]
				{
					new NQComponentRequirement()
					{
						ComponentName = "TestComponent1",
						Version = new Version(2,0,0,0),
						Condition = NQCondition.Greater | NQCondition.Equal
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp1, testComp2 },
				new INQServiceInfo[] { });

			// TestComponent2 must not be loaded (it needs version >= 2.0.0.0 of TestComponent1)
			Assert.That(!_servManager.IsComponentLoaded("TestComponent2"), "TestComponent2 must not be registered.");
		}

		[Test]
		public void MustNotLoadServiceWithUnsatisfiedComponentRequirement()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
				Requires = new NQComponentRequirement[]
				{
					new NQComponentRequirement()
					{
						ComponentName = "TestComponent_xxxxxxxx"
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { singletonServ });

			// TestServiceTypeSimple must not be loaded (it needs TestComponent_xxxxxxxx to be present)
			Assert.That(!_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple)),
				"TestService.Requirement must not be registered.");
		}

		[Test]
		public void MustNotLoadServiceWithUnsatisfiedVersionRequirement()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp1 = new NQComponentInfo()
			{
				Name = "TestComponent1"
			};
			NQComponentInfo testComp2 = new NQComponentInfo()
			{
				Name = "TestComponent2",
				Version = new Version(1, 0, 0, 0)
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
				Requires = new NQComponentRequirement[]
				{
					new NQComponentRequirement()
					{
						ComponentName = "TestComponent2",
						Version = new Version(2,0,0,0),
						Condition = NQCondition.Greater | NQCondition.Equal
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp1, testComp2 },
				new INQServiceInfo[] { singletonServ });

			// TestServiceTypeSimple must not be loaded (it needs version > 2.0.0.0 of TestComponent2)
			Assert.That(!_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple)),
				"TestService.Requirement must not be registered.");
		}

		[Test]
		public void MustLoadServiceWithSatisfiedVersionRequirement()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp1 = new NQComponentInfo()
			{
				Name = "TestComponent1"
			};
			NQComponentInfo testComp2 = new NQComponentInfo()
			{
				Name = "TestComponent2",
				Version = new Version(1, 0, 0, 0)
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent1",
				ServiceType = typeof(TestServiceTypeSimple),
				Requires = new NQComponentRequirement[]
				{
					new NQComponentRequirement()
					{
						ComponentName = "TestComponent2",
						Version = new Version(2, 0, 0, 0),
						Condition = NQCondition.Lower
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp1, testComp2 },
				new INQServiceInfo[] { singletonServ });

			// TestServiceTypeSimple must not be loaded (it needs version < 2.0.0.0 of TestComponent2)
			Assert.That(_servManager.IsServiceCreatable(typeof(TestServiceTypeSimple)),
				"TestService.Requirement must be registered.");
		}

		[Test]
		public void TestAttachListsMustBeFilled()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo attachListServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1",
					"TestService.AttachList/2"
				}
			};
			NQServiceInfo attachListServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				AttachedTo = new string[]
				{
					"TestService.AttachList/2"
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { attachListServ1, attachListServ2 });

			// Test, if the services of NQTestComponent1 are added to our test AttachList
			Type[] attachList1 = NQServiceManager.Instance.GetAttachedServices("TestService.AttachList/1");
			Type[] attachList2 = NQServiceManager.Instance.GetAttachedServices("TestService.AttachList/2");

			Assert.That(attachList1.Contains<Type>(typeof(TestServiceTypeSimple1)),
				"TestService.AttachList/1 must contain TestService.AttachList1.");
			Assert.That(attachList2.Contains<Type>(typeof(TestServiceTypeSimple1)),
				"TestService.AttachList/2 must contain TestService.AttachList1.");
			Assert.That(attachList2.Contains<Type>(typeof(TestServiceTypeSimple2)),
				"TestService.AttachList/2 must contain TestService.AttachList2.");
		}

		[Test]
		public void GetAttachedServices_MustReturnNullOnEmptyAttachLists()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSimple)
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { singletonServ });

			Assert.That(NQServiceManager.Instance.GetAttachedServices("(Non.existent.AttachList)"), Is.Null);
		}

		[Test]
		public void CreateAttachedServices_MustNotReturnServicesWithIncompatibleTypes()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo attachListServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst1),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1",
				}
			};
			NQServiceInfo attachListServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { attachListServ1, attachListServ2 });

			TestServiceTypeSubst1[] attachedServices =
				NQServiceManager.Instance.CreateAttachedServices<TestServiceTypeSubst1>("TestService.AttachList/1");

			// The array attachedServices must contain only one element of type TestServiceTypeSubst1
			Assert.That(attachedServices.Length == 1);
			Assert.That(attachedServices[0], Is.TypeOf<TestServiceTypeSubst1>());
		}

		[Test]
		public void GetAttachedServices_MustHandleGivenTypesOfServicesOnly()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo attachListServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1",
				}
			};
			NQServiceInfo attachListServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};
			NQServiceInfo attachListSingleServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple3),
				SingleInstance = true,
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { attachListServ1, attachListServ2, attachListSingleServ });

			// With (true, true) we must get all 3 elements
			TestServiceTypeSimple[] attachedServices1 =
				NQServiceManager.Instance.GetAttachedServices<TestServiceTypeSimple>("TestService.AttachList/1", true, true);
			Assert.That(attachedServices1.Length == 3);

			// With (true, false) we should get only 2 elements (multi-instance services only)
			TestServiceTypeSimple[] attachedServices2 =
				NQServiceManager.Instance.GetAttachedServices<TestServiceTypeSimple>("TestService.AttachList/1", true, false);
			Assert.That(attachedServices2.Length == 2);

			// With (false, true) we should get only 1 element (single-instance service only)
			TestServiceTypeSimple[] attachedServices3 =
				NQServiceManager.Instance.GetAttachedServices<TestServiceTypeSimple>("TestService.AttachList/1", false, true);
			Assert.That(attachedServices3.Length == 1);
		}

		[Test]
		public void CreateService_MustThrowExceptionWhenServiceNotFound()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo singletonServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSimple)
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { singletonServ });

			var ex = Assert.Throws<NQServiceLoadingException>(delegate()
				{
					NQServiceManager.Instance.CreateService<object>(typeof(TestServiceTypeSubst1));
				});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.UnknownService));
		}

		[Test]
		public void CreateService_MustReturnSubstitutingService()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo substServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst1)
			};
			NQServiceInfo substServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst2)
			};
			NQServiceInfo substServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst3),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst2)
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { substServ1, substServ2, substServ3 });

			// When standard service substitution works properly, the substitution path
			// SubstitutionTest3 -> SubstitutionTest2
			// defined in NQTestComponent1 should result in an instance of SubstitutionTest3,
			// when referencing SubstitutionTest2!
			object service = NQServiceManager.Instance.CreateService<object>(typeof(TestServiceTypeSubst2));
			Assert.That(service.GetType(), Is.EqualTo(typeof(TestServiceTypeSubst3)));
		}

		[Test]
		public void CreateService_MustReturnSubstitutingServiceHierarchical()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo substServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst1)
			};
			NQServiceInfo substServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst2),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst1)
				}
			};
			NQServiceInfo substServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst3),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst2)
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { substServ1, substServ2, substServ3 });

			// When standard service substitution works properly, the substitution path
			// SubstitutionTest3 -> SubstitutionTest2
			// defined in NQTestComponent1 should result in an instance of SubstitutionTest3,
			// when referencing SubstitutionTest2!
			object service = NQServiceManager.Instance.CreateService<object>(typeof(TestServiceTypeSubst1));
			Assert.That(service.GetType(), Is.EqualTo(typeof(TestServiceTypeSubst3)));
		}

		[Test]
		public void GetService_MustReturnSubstitutingService()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo substServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst1)
			};
			NQServiceInfo substServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst2),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst2)
			};
			NQServiceInfo substServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst3),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst3),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst2)
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { substServ1, substServ2, substServ3 });

			// When standard service substitution works properly, the substitution path
			// SubstitutionTest3 -> SubstitutionTest2
			// defined in NQTestComponent1 should result in an instance of SubstitutionTest3,
			// when referencing SubstitutionTest2!
			object service = NQServiceManager.Instance.GetService<object>(typeof(TestServiceTypeSubst2));
			Assert.That(service.GetType(), Is.EqualTo(typeof(TestServiceTypeSubst3)));
		}

		[Test]
		public void GetService_MustReturnSubstitutingServiceHierarchical()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo substServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst1)
			};
			NQServiceInfo substServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst2),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst2),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst1)
				}
			};
			NQServiceInfo substServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst3),
				ParentComponent = "TestComponent",
				SingleInstance = true,
				ServiceType = typeof(TestServiceTypeSubst3),
				Substitutes = new Type[]
				{
					typeof(TestServiceTypeSubst2)
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { substServ1, substServ2, substServ3 });

			// When standard service substitution works properly, the substitution path
			// SubstitutionTest3 -> SubstitutionTest2
			// defined in NQTestComponent1 should result in an instance of SubstitutionTest3,
			// when referencing SubstitutionTest2!
			object service = NQServiceManager.Instance.GetService<object>(typeof(TestServiceTypeSubst1));
			Assert.That(service.GetType(), Is.EqualTo(typeof(TestServiceTypeSubst3)));
		}

		[Test]
		public void CreateDependentService_MustPassParentToConstructor()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo parentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
			};
			NQServiceInfo childServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeChild),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeChild),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { parentServ, childServ });

			// Create TestService.Parent
			TestServiceTypeSimple testParent = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			// Create TestService.Child and pass the instance of TestServiceParent to it
			TestServiceTypeChild testChild =
				NQServiceManager.Instance.CreateDependentService<TestServiceTypeChild, TestServiceTypeSimple>(typeof(TestServiceTypeChild), testParent);

			Assert.That(testChild.ParentService, Is.EqualTo(testParent));
		}

		[Test]
		public void CreateDependentService_MustCatchNotPassingParentToParametrizedConstructor()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo parentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
			};
			NQServiceInfo childServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeChild),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeChild),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { parentServ, childServ });

			// Create TestService.Parent
			TestServiceTypeSimple testParent = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			var ex = Assert.Throws<NQServiceLoadingException>(delegate()
			{
				// Create child service and pass the instance of TestServiceParent to it
				TestServiceTypeChild testChild =
						NQServiceManager.Instance.CreateService<TestServiceTypeChild>(typeof(TestServiceTypeChild));
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.NoConstructor));
		}

		[Test]
		public void CreateDependentService_MustPassParentToInitDependent()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo parentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
			};
			NQServiceInfo childServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeChildProprietary),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeChildProprietary),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { parentServ, childServ });

			// Create TestService.Parent
			TestServiceTypeSimple testParent = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			// Create TestService.Child and pass the instance of TestServiceParent to it
			TestServiceTypeChildProprietary testChild =
				NQServiceManager.Instance.CreateDependentService<TestServiceTypeChildProprietary, TestServiceTypeSimple>(
				typeof(TestServiceTypeChildProprietary), testParent);

			Assert.That(testChild.ParentService, Is.EqualTo(testParent));
		}

		[Test]
		public void CreateDependentServiceDirect_MustPassParentToConstructor()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo parentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
			};
			NQServiceInfo childServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeChild),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeChild),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { parentServ, childServ });

			// Create TestService.Parent
			TestServiceTypeSimple testParent = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			// Create TestService.Child and pass the instance of TestServiceParent to it
			TestServiceTypeChild testChild =
				NQServiceManager.Instance.CreateDependentServiceDirect<TestServiceTypeChild, TestServiceTypeSimple>(
				typeof(TestServiceTypeChild), testParent);

			Assert.That(testChild.ParentService, Is.EqualTo(testParent));
		}

		[Test]
		public void CreateDependentServiceDirect_MustPassParentToInitDependent()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo parentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple),
			};
			NQServiceInfo childServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeChildProprietary),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeChildProprietary),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { parentServ, childServ });

			// Create TestService.Parent
			TestServiceTypeSimple testParent = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			// Create TestService.Child and pass the instance of TestServiceParent to it
			TestServiceTypeChildProprietary testChild =
				NQServiceManager.Instance.CreateDependentServiceDirect<TestServiceTypeChildProprietary, TestServiceTypeSimple>(
				typeof(TestServiceTypeChildProprietary), testParent);

			Assert.That(testChild.ParentService, Is.EqualTo(testParent));
		}

		[Test]
		public void MustInvokeAndQuitServiceProprietary()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo invokableServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeInvokableProprietary),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeInvokableProprietary),
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { invokableServ });

			INQInvokableService service =
				NQServiceManager.Instance.CreateService<INQInvokableService>(typeof(TestServiceTypeInvokableProprietary));
			// After invoking the service, the OperationPerforming property must be set to true
			NQServiceManager.Instance.InvokeService(service);
			Assert.That(((TestServiceTypeInvokableProprietary) service).OperationPerforming);

			// After quitting the operation, the OperationPerforming property must be set back to false
			NQServiceManager.Instance.QuitService(service);
			Assert.That(!((TestServiceTypeInvokableProprietary) service).OperationPerforming);
		}

		[Test]
		public void MustInvokeAndQuitService()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};
			NQServiceInfo invokableServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeInvokable),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeInvokable),
				InvokeMethod = typeof(TestServiceTypeInvokable).GetMethod("InvokeService"),
				QuitMethod = typeof(TestServiceTypeInvokable).GetMethod("QuitService")
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { invokableServ });

			TestServiceTypeInvokable service =
				NQServiceManager.Instance.CreateService<TestServiceTypeInvokable>(typeof(TestServiceTypeInvokable));
			// After invoking the service, the OperationPerforming property must be set to true
			NQServiceManager.Instance.InvokeService(service);
			Assert.That(service.OperationPerforming);

			// After quitting the operation, the OperationPerforming property must be set back to false
			NQServiceManager.Instance.QuitService(service);
			Assert.That(!service.OperationPerforming);
		}

		[Test]
		public void MustAutoInjectServices()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};
			NQServiceInfo injectedServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple3),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple1),
						Interface = typeof(TestServiceTypeSimple)
					},
					new NQAutoInjection()
					{
						BoundAttachList = "TestService.AttachList/1",
						Interface = typeof(TestServiceTypeSimple),
						InjectFromAttachList = true
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2, injectedServ3 });

			// Now we create an instance of "TestService.InjectionDest" and check, if the service instances have been passed properly
			var autoInjectServ =
				NQServiceManager.Instance.CreateService<TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>>(
				typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>));

			Assert.That(autoInjectServ.Injection1, Is.Not.Null);
			Assert.That(autoInjectServ.Injection1, Is.TypeOf<TestServiceTypeSimple1>());
			Assert.That(autoInjectServ.Injection2, Is.Not.Null);
			Assert.That(autoInjectServ.Injection2, Is.TypeOf<TestServiceTypeSimple[]>());
			Assert.That(autoInjectServ.Injection2.Length == 2);
		}

		[Test]
		public void MustCheckAutoInjectionIntegrityOnLoading()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};
			NQServiceInfo injectedServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple3),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple1),
						Interface = typeof(TestServiceTypeSimple)
					},
					new NQAutoInjection()
					{
						BoundAttachList = "TestService.AttachList/1",
						Interface = typeof(TestServiceTypeSimple),
						InjectFromAttachList = true
					}
				}
			};

			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
					new INQComponentInfo[] { testComp },
					new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2, injectedServ3 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.NoConstructor));
		}

		[Test]
		public void MustCheckServiceExistenceInAutoInjectionOnLoading()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};
			NQServiceInfo injectedServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple3),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple3),
				AttachedTo = new string[]
				{
					"TestService.AttachList/1"
				}
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple[]>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeChild), // Unregistered service interface
						Interface = typeof(TestServiceTypeSimple)
					},
					new NQAutoInjection()
					{
						BoundAttachList = "TestService.AttachList/1",
						Interface = typeof(TestServiceTypeSimple),
						InjectFromAttachList = true
					}
				}
			};

			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
					new INQComponentInfo[] { testComp },
					new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2, injectedServ3 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.UnresolvedAutoInjection));
		}

		//[Test]
		//public void MustAutoInjectAndPassItselfToDependentServices()
		//{
		//  // Build metadata dummies for the test
		//  NQComponentInfo testComp = new NQComponentInfo()
		//  {
		//    Name = "TestComponent"
		//  };

		//  // Services to be injected
		//  NQServiceInfo injectedServ1 = new NQServiceInfo()
		//  {
		//    ServiceInterface = typeof(TestServiceTypeChild1),
		//    ParentComponent = "TestComponent",
		//    ServiceType = typeof(TestServiceTypeChild1)
		//  };
		//  NQServiceInfo injectedServ2 = new NQServiceInfo()
		//  {
		//    ServiceInterface = typeof(TestServiceTypeChild2),
		//    ParentComponent = "TestComponent",
		//    ServiceType = typeof(TestServiceTypeChild2),
		//    AttachedTo = new string[]
		//    {
		//      "TestService.AttachList/1"
		//    }
		//  };
		//  NQServiceInfo injectedServ3 = new NQServiceInfo()
		//  {
		//    ServiceInterface = typeof(TestServiceTypeChild3),
		//    ParentComponent = "TestComponent",
		//    ServiceType = typeof(TestServiceTypeChild3),
		//    AttachedTo = new string[]
		//    {
		//      "TestService.AttachList/1"
		//    }
		//  };

		//  // The service where the services above are injected to
		//  NQServiceInfo injectionDest = new NQServiceInfo()
		//  {
		//    ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeChild, TestServiceTypeChild[]>),
		//    ParentComponent = "TestComponent",
		//    ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeChild, TestServiceTypeChild[]>),
		//    AutoInjections = new NQAutoInjection[]
		//    {
		//      new NQAutoInjection()
		//      {
		//        BoundService = typeof(TestServiceTypeChild1),
		//        Interface = typeof(TestServiceTypeChild),
		//        InjectAsDependent = true
		//      },
		//      new NQAutoInjection()
		//      {
		//        BoundAttachList = "TestService.AttachList/1",
		//        Interface = typeof(TestServiceTypeChild),
		//        InjectFromAttachList = true,
		//        InjectAsDependent = true
		//      }
		//    }
		//  };

		//  this.SetupManager(NQHostMode.Console,
		//    new INQComponentInfo[] { testComp },
		//    new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2, injectedServ3 });

		//  // Now we create an instance of "TestService.InjectionDest" and check, if the service instances have been passed properly
		//  var autoInjectServ =
		//    NQServiceManager.Instance.CreateService<TestServiceTypeAutoInjection2<TestServiceTypeChild, TestServiceTypeChild[]>>(
		//    typeof(TestServiceTypeAutoInjection2<TestServiceTypeChild, TestServiceTypeChild[]>));

		//  Assert.That(autoInjectServ.Injection1.ParentService, Is.EqualTo(autoInjectServ));
		//  Assert.That(autoInjectServ.Injection2[0], Is.EqualTo(autoInjectServ));
		//}

		[Test(Description = "Must correctly handle passing null as the parent to dependent services through CreateDependentService.")]
		public void MustPassNullAsParentToDependentServices()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// The dependent service to pass null to
			NQServiceInfo dependentServ = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection<TestServiceTypeSimple>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection<TestServiceTypeSimple>)
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { dependentServ });

			// Create an instance of the dependent service
			// and pass null (as parent service) to it.
			var autoInjectServ =
				NQServiceManager.Instance.CreateDependentService
				<TestServiceTypeAutoInjection<TestServiceTypeSimple>, TestServiceTypeSimple>
				(typeof(TestServiceTypeAutoInjection<TestServiceTypeSimple>), null);

			Assert.That(autoInjectServ.Injection, Is.Null);
		}


		[Test(Description = "When Override parameter is not set, handle services passed through CreateDependentService() independently from auto-injection.")]
		public void MustAutoInjectThroughCreateDependentServiceWithoutOverride()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple)
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple),
						Interface = typeof(TestServiceTypeSimple)
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { injectionDest, injectedServ1 });

			// Firstly we create a parent service, that we can pass (= inject) into "TestService.InjectionDest"
			var parentServ = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple));

			// Now we create an instance of "TestService.InjectionDest" as a dependent service and check,
			// if parentServ has been injected properly.
			var autoInjectServ =
				NQServiceManager.Instance.CreateDependentService
				<TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>, TestServiceTypeSimple>
				(typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>), parentServ);

			Assert.That(autoInjectServ.Injection1, Is.EqualTo(parentServ));
		}

		[Test(Description = "When Override parameter is set, auto-inject services passed through CreateDependentService(). First parameter is overridable.")]
		public void MustAutoInjectThroughCreateDependentServiceWithOverrideAsFirst()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2)
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple1),
						Interface = typeof(TestServiceTypeSimple),
						Overridable = true
					},
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple2),
						Interface = typeof(TestServiceTypeSimple)
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2 });

			// Firstly we create a parent service, that we can pass (= inject) into "TestService.InjectionDest"
			var parentServ = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple1));

			// Now we create an instance of "TestService.InjectionDest" as a dependent service and check,
			// if parentServ has been injected properly.
			var autoInjectServ =
				NQServiceManager.Instance.CreateDependentService
				<TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>, TestServiceTypeSimple>
				(typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>), parentServ);

			Assert.That(autoInjectServ.Injection1, Is.EqualTo(parentServ));
		}

		[Test(Description = "When Override parameter is set, auto-inject services passed through CreateDependentService(). Second parameter is overridable.")]
		public void MustAutoInjectThroughCreateDependentServiceWithOverrideAsSecond()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1)
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2)
			};

			// The service where the services above are injected to
			NQServiceInfo injectionDest = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple1),
						Interface = typeof(TestServiceTypeSimple),
					},
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeSimple2),
						Interface = typeof(TestServiceTypeSimple),
						Overridable = true
					}
				}
			};

			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { injectionDest, injectedServ1, injectedServ2 });

			// Firstly we create a parent service, that we can pass (= inject) into "TestService.InjectionDest"
			var parentServ = NQServiceManager.Instance.CreateService<TestServiceTypeSimple>(typeof(TestServiceTypeSimple2));

			// Now we create an instance of "TestService.InjectionDest" as a dependent service and check,
			// if parentServ has been injected properly.
			var autoInjectServ =
				NQServiceManager.Instance.CreateDependentService
				<TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>, TestServiceTypeSimple>
				(typeof(TestServiceTypeAutoInjection2<TestServiceTypeSimple, TestServiceTypeSimple>), parentServ);

			Assert.That(autoInjectServ.Injection2, Is.EqualTo(parentServ));
		}

		[Test(Description = "The scenario of 'Service2 substitues Service1, but does not implement its interface' etc. must be avoided.")]
		public void MustAvoidSubstitutionDefinitionWithIncompatibleServiceInterfaces()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo cyclicServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1),
			};
			NQServiceInfo cyclicServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSubst1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSubst1),
				Substitutes = new Type[] { typeof(TestServiceTypeSimple1) }
			};

			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
					new INQComponentInfo[] { testComp },
					new INQServiceInfo[] { cyclicServ1, cyclicServ2 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.SubstitutorInterfaceMismatch));
		}

		[Test(Description = "The scenario of 'Service1 substitues Service2, Service2 substitutes Service1' etc. must be avoided.")]
		public void MustAvoidCyclicSubstitution()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo cyclicServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple1),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple1),
				Substitutes = new Type[] { typeof(TestServiceTypeSimple2) }
			};
			NQServiceInfo cyclicServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeSimple2),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeSimple2),
				Substitutes = new Type[] { typeof(TestServiceTypeSimple1) }
			};

			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
					new INQComponentInfo[] { testComp },
					new INQServiceInfo[] { cyclicServ1, cyclicServ2 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.CircularSubstitution));
		}

		[Test(Description = "The scenario of 'Service1 gets Service2 injected, Service2 gets Service1 injected' must be avoided.")]
		public void MustAvoidCyclicInjectionDefinition()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection<object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection<object>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection1<object>),
						Interface = typeof(object),
					}
				}
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection1<object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection1<object>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection<object>),
						Interface = typeof(object),
					}
				}
			};

			// There is a "TestService.Injected1", that gets "TestService.Injected2" injected,
			// that gets "TestService.Injected1". The cyclic definition must result in an exception
			// when loading!
			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
				 new INQComponentInfo[] { testComp },
				 new INQServiceInfo[] { injectedServ1, injectedServ2 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.CircularAutoInjection));
		}

		[Test(Description = "The scenario of 'Service1 gets Service2 and Service3 injected, Service3 again injects Service2' must be allowed.")]
		public void MustDetectAllowedInjectionOfSameServicesInHierarchy()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection2<object, object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection<object>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection<object>),
						Interface = typeof(object),
					},
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection1<object>),
						Interface = typeof(object),
					}
				}
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection<object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection<object>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection1<object>),
						Interface = typeof(object),
					}
				}
			};
			NQServiceInfo injectedServ3 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection1<object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection1<object>)
			};

			// The structure above is ok, no exception may be thrown!
			this.SetupManager(NQHostMode.Console,
				new INQComponentInfo[] { testComp },
				new INQServiceInfo[] { injectedServ1, injectedServ2, injectedServ3 });
		}

		[Test(Description = "The scenario of 'Service1 gets AttachList with Service2 injected, Service2 gets Service1 injected' must be avoided.")]
		public void MustAvoidCyclicInjectionDefinitionWithAttachLists()
		{
			// Build metadata dummies for the test
			NQComponentInfo testComp = new NQComponentInfo()
			{
				Name = "TestComponent"
			};

			// Services to be injected
			NQServiceInfo injectedServ1 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection<object[]>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection<object[]>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundAttachList = "TestService.AttachList/1",
						Interface = typeof(object),
						InjectFromAttachList = true,
					}
				}
			};
			NQServiceInfo injectedServ2 = new NQServiceInfo()
			{
				ServiceInterface = typeof(TestServiceTypeAutoInjection1<object>),
				ParentComponent = "TestComponent",
				ServiceType = typeof(TestServiceTypeAutoInjection1<object>),
				AutoInjections = new NQAutoInjection[]
				{
					new NQAutoInjection()
					{
						BoundService = typeof(TestServiceTypeAutoInjection<object[]>),
						Interface = typeof(object),
					}
				},
				AttachedTo = new string[] { "TestService.AttachList/1" }
			};

			// There is a "TestService.Injected1", that gets "TestService.Injected2" injected,
			// that gets "TestService.Injected1". The cyclic definition must result in an exception
			// when loading!
			var ex = Assert.Throws<NQServiceDefinitionException>(delegate()
			{
				this.SetupManager(NQHostMode.Console,
				 new INQComponentInfo[] { testComp },
				 new INQServiceInfo[] { injectedServ1, injectedServ2 });
			});
			Assert.That(ex.Reason, Is.EqualTo(NQErrorReason.CircularAutoInjection));
		}

		[Test(Description = "Log messages of INFO level must be reported, DEBUG messages must be filtered out.")]
		public void MustReportInfoLogsAndFilterOutDebugLogs()
		{
			// Create Service Manager without components and services
			this.SetupManager(NQHostMode.Console, null, null);

			bool messageLogged = false;
			NQServiceManager.Instance.MessageLogged += delegate(object sender, NQLogEventArgs e)
			{
				messageLogged = true;
			};
			NQServiceManager.Instance.LogEventFilter = NQLogType.Info;

			// Log an INFO message
			NQServiceManager.Instance.LogMessage(NQLogType.Info, "Some INFO message");
			Assert.That(messageLogged, Is.True);

			// Log an DEBUG message
			messageLogged = false;
			NQServiceManager.Instance.LogMessage(NQLogType.Debug, "Some DEBUG message");
			Assert.That(messageLogged, Is.False);
		}

		[Test(Description = "All log messages must be reported")]
		public void MustReportAllLogs()
		{
			// Create Service Manager without components and services
			this.SetupManager(NQHostMode.Console, null, null);

			bool messageLogged = false;
			NQServiceManager.Instance.MessageLogged += delegate(object sender, NQLogEventArgs e)
			{
				messageLogged = true;
			};
			NQServiceManager.Instance.LogEventFilter = NQLogType.All;

			// Log an INFO message
			NQServiceManager.Instance.LogMessage(NQLogType.Info, "Some INFO message");
			Assert.That(messageLogged, Is.True);

			// Log an DEBUG message
			messageLogged = false;
			NQServiceManager.Instance.LogMessage(NQLogType.Debug, "Some DEBUG message");
			Assert.That(messageLogged, Is.True);
		}
	}
}
